use std::any::Any;
use std::fmt::Debug;
use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::oneshot::Sender;
use crate::{ChannelId, RpcContext, RpcEvent, RpcResult};
use crate::sender::RpcSender;

pub trait ConnectionEvent: Send + Sync + Any + Debug {
    fn handle(self, manager: &mut dyn ConnectionManageable) -> RpcResult<()>;
}

pub trait ConnectionManageable {
    fn handle_event(&mut self, event: Box<dyn ConnectionEvent>);
}

pub enum ConnectionManagerDataEvent {
    Read(ReadData),
    Idle{ write_idle_time: Option<u64>, read_idle_time: Option<u64>, sender: RpcSender, listeners: Arc<Vec<Box<dyn IdleListener>>> },
    Idles{ data: Vec<IdleData>, sender: RpcSender, listeners: Arc<Vec<Box<dyn IdleListener>>>},
}

impl ConnectionEvent for ConnectionManagerDataEvent {
    fn handle(self, manager: &mut dyn ConnectionManageable) -> RpcResult<()> {
        manager.handle_event(Box::new(self));
        Ok(())
    }
}

impl Debug for ConnectionManagerDataEvent {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ConnectionManagerDataEvent::Read(data) => {
                write!(f, "ConnectionManagerDataEvent read")
            }
            ConnectionManagerDataEvent::Idle { .. } => {
                write!(f, "ConnectionManagerDataEvent idle")
            }
            ConnectionManagerDataEvent::Idles { .. } => {
                write!(f, "ConnectionManagerDataEvent idles")
            }
        }

    }
}

#[derive(Debug)]
pub struct WriteData {
    pub channel_id: ChannelId,
    pub local_seq: String,
    pub data: Vec<u8>,
    pub has_response: bool,
    pub sender: Option<Sender<ResponseData>>,
}

impl WriteData {
    pub fn new(channel_id: ChannelId, local_seq: String, data: Vec<u8>,
               has_response: bool, sender: Option<Sender<ResponseData>>) -> WriteData {
        Self {
            channel_id,
            local_seq,
            data,
            has_response,
            sender,
        }
    }
}

#[derive(Debug)]
pub struct ResponseData {
    pub local_seq: String,
    pub is_success: bool,
    pub data: Vec<u8>,
}

impl ResponseData {
    pub fn new(local_seq: String, is_success: bool, data: Vec<u8>) -> ResponseData {
        Self {
            local_seq,
            is_success,
            data,
        }
    }
}

pub struct ReadData {
    pub channel_id: ChannelId,
    pub length: usize,
}

impl ReadData {
    pub fn new(channel_id: ChannelId, length: usize) -> ReadData {
        Self {
            channel_id,
            length,
        }
    }
}

pub struct IdleData {
    pub write_idle_time: Option<u64>,
    pub read_idle_time: Option<u64>,
}

impl IdleData {
    pub fn new(write_idle_time: Option<u64>, read_idle_time: Option<u64>) -> IdleData {
        Self {
            write_idle_time,
            read_idle_time,
        }
    }
}

#[derive(Debug)]
pub struct IdleResultData {
    pub channel_id: ChannelId,

    write_idle_time: Option<u64>,
    read_idle_time: Option<u64>,
}

impl IdleResultData {
    pub fn new(channel_id: ChannelId, write_idle_time: Option<u64>, read_idle_time: Option<u64>) -> Self {
        Self {
            channel_id,
            write_idle_time,
            read_idle_time,
        }
    }
}

pub trait IdleListener: Send + Sync {
    fn get_write_idle_time(&self) -> Option<u64>;
    fn get_read_idle_time(&self) -> Option<u64>;
    fn handle(&self, context: &RpcContext, idle_data: &IdleResultData) -> RpcResult<()>;

    fn to_connection_event(&self, sender: RpcSender, listeners: Arc<Vec<Box<dyn IdleListener>>>) -> ConnectionManagerDataEvent {
        ConnectionManagerDataEvent::Idle {
            write_idle_time: self.get_write_idle_time(),
            read_idle_time: self.get_read_idle_time(),
            sender,
            listeners,
        }
    }

    fn to_idle_data(&self)-> IdleData {
        IdleData {
            write_idle_time: self.get_write_idle_time(),
            read_idle_time: self.get_read_idle_time(),
        }
    }
}

pub struct RpcIdleEvent {
    data: Vec<IdleResultData>,
    idle_listeners: Arc<Vec<Box<dyn IdleListener>>>,
}

impl RpcIdleEvent {
    pub fn new(data: Vec<IdleResultData>, idle_listeners: Arc<Vec<Box<dyn IdleListener>>>) -> Self {
        Self {
            data,
            idle_listeners,
        }
    }
}

impl RpcEvent for RpcIdleEvent {
    fn consume(&self, context: RpcContext) -> RpcResult<()> {
        for data in self.data.iter() {
            for listener in self.idle_listeners.iter() {
                listener.handle(&context, data)?;
            }
        }
        Ok(())
    }
}